package xyz.yuzegod.megawalls.game;

import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPCRegistry;
import org.bukkit.*;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scoreboard.Team;
import xyz.yuzegod.megawalls.MegaWalls;
import xyz.yuzegod.megawalls.classes.Classes;
import xyz.yuzegod.megawalls.classes.ClassesManager;
import xyz.yuzegod.megawalls.config.FileConfig;
import xyz.yuzegod.megawalls.event.GameStartEvent;
import xyz.yuzegod.megawalls.game.stage.StageManager;
import xyz.yuzegod.megawalls.game.team.TeamColor;
import xyz.yuzegod.megawalls.inventory.SpectatorInventory;
import xyz.yuzegod.megawalls.stats.EffectStatsContainer;
import xyz.yuzegod.megawalls.stats.KitStatsContainer;
import xyz.yuzegod.megawalls.timer.*;

import java.util.ArrayList;
import java.util.List;

public class Game
{
    private String mapName;
    private GameType gameType;
    private GameState state;
    private GameTimer gameTimer;
    private StageManager stageManager;
    private Location lobbyLocation;
    private GameRegion centerArea;
    private List<GameTeam> teams;
    private List<GameParty> parties;
    private List<GameWall> walls;
    private long startTime;
    private boolean wallsFall;
    private boolean witherAngry;
    private boolean deathMatch;
    private GameOverTimer gameOverTimer;
    private int minPlayers;
    private int maxPlayers;
    private int teamSize;
    
    private Game() {
        this.mapName = null;
        this.gameType = GameType.NORMAL;
        this.state = GameState.STOP;
        this.gameTimer = null;
        this.stageManager = null;
        this.lobbyLocation = null;
        this.centerArea = null;
        this.teams = new ArrayList<GameTeam>();
        this.parties = new ArrayList<GameParty>();
        this.walls = new ArrayList<GameWall>();
        this.startTime = 0L;
        this.wallsFall = false;
        this.witherAngry = false;
        this.deathMatch = false;
        this.gameOverTimer = null;
    }
    
    public static boolean build(final FileConfig config, final CommandSender sender) {
        try {
            for (final NPCRegistry npcRegistry : CitizensAPI.getNPCRegistries()) {
                npcRegistry.deregisterAll();
            }
            CitizensAPI.getDataFolder().delete();
            final Game game = new Game();
            game.teamSize = MegaWalls.getInstance().getConfig().getInt("team-size", 20);
            game.mapName = config.getString("mapname", "默认");
            game.gameType = GameType.valueOf(config.getString("type", "NORMAL").toUpperCase());
            game.maxPlayers = ((game.gameType == GameType.DUEL) ? (game.teamSize * 2) : (game.teamSize * 4));
            game.minPlayers = game.maxPlayers / 4;
            game.lobbyLocation = config.getLocation("lobby");
            game.centerArea = new GameRegion(config.getBlockLocation("center-area.loc1"), config.getBlockLocation("center-area.loc2"));
            for (final TeamColor teamColor : TeamColor.values()) {
                Label_0241: {
                    if (game.gameType == GameType.DUEL) {
                        if (teamColor == TeamColor.YELLOW) {
                            break Label_0241;
                        }
                        if (teamColor == TeamColor.GREEN) {
                            break Label_0241;
                        }
                    }
                    game.teams.add(GameTeam.build(config, teamColor, sender));
                }
            }
            final ConfigurationSection section = config.getConfigurationSection("walls");
            for (final String key : section.getKeys(false)) {
                final GameWall gameWall = new GameWall(config.getBlockLocation("walls." + key + ".loc1"), config.getBlockLocation("walls." + key + ".loc2"));
                game.walls.add(gameWall);
            }
            MegaWalls.getInstance().setGame(game);
            game.init();
            return true;
        }
        catch (Exception e) {
            sender.sendMessage("§c加载游戏时出错: §b" + e.getMessage());
            return false;
        }
    }
    
    public void init() {
        this.setState(GameState.LOBBY);
        Bukkit.getScheduler().runTaskTimer((Plugin)MegaWalls.getInstance(), (Runnable)(this.gameTimer = new GameTimer()), 0L, 20L);
        this.stageManager = new StageManager(this);
        Bukkit.getScheduler().runTaskTimer((Plugin)MegaWalls.getInstance(), (Runnable)new ScoreBoardTimer(this), 0L, 20L);
    }
    
    public void onStart() {
        if (!this.isWaiting()) {
            return;
        }
        Bukkit.getServer().getPluginManager().callEvent((Event)new GameStartEvent(this));
        this.setState(GameState.INGAME);
        this.startTime = System.currentTimeMillis();
        this.moveFreePlayersToTeam();
        this.stageManager.start();
        ClassesManager.start();
        for (final Entity entity : Bukkit.getWorld("world").getLivingEntities()) {
            if (entity instanceof Player) {
                continue;
            }
            entity.remove();
        }
        for (final GamePlayer gamePlayer : MegaWalls.getIngame()) {
            gamePlayer.createEnderChest();
            gamePlayer.getPlayerStats().setCacheSelected(ClassesManager.getSelected(gamePlayer));
            final GameTeam gameTeam = gamePlayer.getGameTeam();
            final EffectStatsContainer effectStats = gamePlayer.getPlayerStats().getEffectStats();
            gamePlayer.sendMessage(effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + "你被分配到" + gameTeam.getTeamColor().getText() + "队");
            gamePlayer.sendMessage("§e§l高墙在§b§l" + ((this.gameType == GameType.NORMAL) ? 6 : 10) + "分钟§e§l后倒塌。");
            final Player player = gamePlayer.getPlayer();
            player.getInventory().clear();
            player.getInventory().setArmorContents((ItemStack[])null);
            player.setLevel(0);
            player.setExp(0.0f);
            player.setGameMode(GameMode.SURVIVAL);
            player.sendMessage("§a▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬");
            player.sendMessage("§f                                       §l超级战墙");
            player.sendMessage(" ");
            player.sendMessage("                                §e§l高墙还有" + ((this.gameType == GameType.NORMAL) ? 6 : 10) + "分钟倒塌！");
            player.sendMessage("                      §e§l采集资源， 并装备好自己去摧毁敌人");
            player.sendMessage("                            §e§l及敌方凋零， 击败其他队伍！");
            player.sendMessage(" ");
            player.sendMessage("§a▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬");
            final Classes classes = gamePlayer.getPlayerStats().getSelected();
            final KitStatsContainer kitStats = gamePlayer.getPlayerStats().getKitStats(classes);
            player.setMaxHealth((kitStats.getLevel() >= 2) ? 44.0 : 40.0);
            gamePlayer.sendTitle("§e§l超级战墙", effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + gameTeam.getTeamColor().getText() + "队", 10, 40, 10);
            player.addPotionEffect(new PotionEffect(PotionEffectType.SATURATION,60*20*20,10));
            player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 9999*20, 4));
            player.setFoodLevel(20);
        }
        for (final GameTeam gameTeam2 : this.teams) {
            gameTeam2.spawnWither();
        }
        Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
            @Override
            public void run() {
                Game.this.registerScoreboardTeams();
                for (final GameTeam gameTeam : Game.this.teams) {
                    gameTeam.teleportToSpawn();
                }
            }
        }, 10L);
        this.gameTimer.setTime(3925);
        Bukkit.getScheduler().runTaskTimer((Plugin)MegaWalls.getInstance(), (Runnable)new CompassTimer(), 0L, 5L);
        Bukkit.getScheduler().runTaskTimer((Plugin)MegaWalls.getInstance(), (Runnable)new ObjectiveTimer(), 0L, 20L);
        Bukkit.getScheduler().runTaskTimer((Plugin)MegaWalls.getInstance(), (Runnable)new SkillTimer(), 0L, 5L);
    }
    
    public void onStop() {
        for (final GamePlayer gamePlayer : MegaWalls.getIngame()) {
            final Player player = gamePlayer.getPlayer();
            player.teleport(this.lobbyLocation);
            player.setGameMode(GameMode.SURVIVAL);
            player.getInventory().clear();
            player.getInventory().setArmorContents((ItemStack[])null);
            player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
            MegaWalls.getInstance().tpToLobby(player);
        }
        this.stageManager.stop();
        this.setState(GameState.STOP);
        for (final GamePlayer gamePlayer : FakePlayer.list) {
            FakePlayer.list.remove(gamePlayer);
            MegaWalls.updateRejoin(gamePlayer, "none", System.currentTimeMillis());
        }
    }
    
    public void forceStart() {
        this.onStart();
    }
    
    public boolean isOver() {
        int alives = 0;
        for (final GameTeam gameTeam : this.teams) {
            if (!gameTeam.isDead()) {
                ++alives;
            }
        }
        return alives <= 1;
    }
    
    public void registerScoreboardTeams() {
        for (final Player player : Bukkit.getOnlinePlayers()) {
            this.registerScoreboardTeams(player);
        }
    }
    
    public void registerScoreboardTeams(final Player player) {
        final GamePlayer gamePlayer1 = GamePlayer.get(player.getUniqueId());
        final EffectStatsContainer effectStats = gamePlayer1.getPlayerStats().getEffectStats();
        int i = 0;
        for (final Player player2 : Bukkit.getOnlinePlayers()) {
            ++i;
            final GamePlayer gamePlayer2 = GamePlayer.get(player2.getUniqueId());
            final GameTeam gameTeam = gamePlayer2.getGameTeam();
            final String name = ((gameTeam != null) ? gameTeam.getTeamColor().name() : "SPECTATOR") + String.valueOf(i);
            if (player.getScoreboard().getTeam(name) != null) {
                continue;
            }
            final Team team = player.getScoreboard().registerNewTeam(name);
            final Classes classes = ClassesManager.getSelected(gamePlayer2);
            final KitStatsContainer kitStats = gamePlayer2.getPlayerStats().getKitStats(classes);
            if (gamePlayer2.isSpectator()) {
                team.setPrefix("§7✖ " + ((gameTeam != null) ? (effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + " ") : "§9"));
                team.addEntry(gamePlayer2.getName());
            }
            else {
                final String suffix = (kitStats.isEnableGoldTag() ? "§6" : "§7") + "[" + classes.getDisplayName() + "]";
                if (!this.isWallsFall()) {
                    final String prefix = (gamePlayer1.getGameTeam() != null && gamePlayer1.getGameTeam().isInTeam(gamePlayer2)) ? (effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + (effectStats.isEnablePrefix() ? gamePlayer2.getGameTeam().getTeamColor().getTag() : "") + " " + (effectStats.isEnableItalic() ? (effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + "" + ChatColor.ITALIC) : "")) : "§k§l";
                    final String suffix2 = (gamePlayer1.getGameTeam() != null && gamePlayer1.getGameTeam().isInTeam(gamePlayer2)) ? (" " + suffix) : "";
                    team.setPrefix(prefix);
                    team.setSuffix(suffix2);
                    team.addEntry(gamePlayer2.getName());
                }
                else {
                    if (gamePlayer2.getGameTeam() == null) {
                        continue;
                    }
                    if (!gamePlayer2.getGameTeam().isInTeam(gamePlayer1)) {
                        team.setPrefix(effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + (effectStats.isEnablePrefix() ? gamePlayer2.getGameTeam().getTeamColor().getTag() : "") + " " + (effectStats.isEnableBold() ? (effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + "" + ChatColor.BOLD) : ""));
                    }
                    else {
                        team.setPrefix(effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + (effectStats.isEnablePrefix() ? gamePlayer2.getGameTeam().getTeamColor().getTag() : "") + " " + (effectStats.isEnableItalic() ? (effectStats.getColor(gamePlayer2.getGameTeam().getTeamColor()).getChatColor() + "" + ChatColor.ITALIC) : ""));
                    }
                    team.setSuffix(" " + suffix);
                    team.addEntry(gamePlayer2.getName());
                }
            }
        }
    }
    
    public String[] getScoreboardTeamLines(final GamePlayer gamePlayer) {
        final EffectStatsContainer effectStats = gamePlayer.getPlayerStats().getEffectStats();
        final String[] lines = new String[(this.gameType == GameType.DUEL) ? 2 : 4];
        for (final GameTeam gameTeam : this.teams) {
            final boolean isInTeam = gameTeam.isInTeam(gamePlayer);
            final StringBuffer sb = new StringBuffer();
            if (!gameTeam.isDead()) {
                sb.append(effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + gameTeam.getTeamColor().getTag() + " ");
                sb.append(isInTeam ? "" : "§f");
                sb.append(gameTeam.isWitherDead() ? "玩家" : ("凋零 " + effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + "❤"));
                sb.append("§7： " + (gameTeam.isWitherDead() ? Integer.valueOf(gameTeam.getAlivePlayers().size()) : ("" + effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + (int)gameTeam.getTeamWither().getHealth())));
            }
            else {
                sb.append(ChatColor.GRAY + gameTeam.getTeamColor().getText() + "已淘汰！");
            }
            if (gamePlayer.isSpectator()) {
                for (int i = 0; i < lines.length; ++i) {
                    if (lines[i] == null) {
                        lines[i] = sb.toString();
                        break;
                    }
                }
            }
            else if (isInTeam) {
                lines[0] = sb.toString();
            }
            else {
                for (int i = 1; i < lines.length; ++i) {
                    if (lines[i] == null) {
                        lines[i] = sb.toString();
                        break;
                    }
                }
            }
        }
        return lines;
    }
    
    public void openSpectatorInventory(final GamePlayer player) {
        if (!player.isSpectator()) {
            return;
        }
        SpectatorInventory.alivePlayers(MegaWalls.getIngame()).open(player.getPlayer());
    }
    
    public GameTeam getWinner() {
        for (final GameTeam team : this.teams) {
            if (!team.isDead()) {
                return team;
            }
        }
        return null;
    }
    
    public boolean isTeamRegion(final Location location) {
        for (final GameTeam gameTeam : this.teams) {
            if (gameTeam.getRegion().isInRegion(location)) {
                return true;
            }
        }
        return false;
    }
    
    public boolean isProtected(final Location location) {
        for (final GameTeam gameTeam : this.teams) {
            if (gameTeam.getCastleRegion().isInRegion(location) && !gameTeam.isWitherDead()) {
                return true;
            }
        }
        return false;
    }
    
    public boolean isWall(final Location location) {
        for (final GameWall gameWall : this.walls) {
            if (gameWall.isInWall(location)) {
                return true;
            }
        }
        return false;
    }
    
    public boolean isUnbreakable(final Location location) {
        return this.isProtected(location) || (!this.getCenterArea().isInRegion(location) && !this.isTeamRegion(location)) || (this.isWall(location) && !this.isWallsFall());
    }
    
    public boolean isWaiting() {
        return this.state == GameState.LOBBY;
    }
    
    public boolean isStarted() {
        return this.state == GameState.INGAME;
    }
    
    public String getFormattedTime(final int time) {
        final int min = (int)Math.floor(time / 60);
        final int sec = time % 60;
        final String minStr = (min < 10) ? ("0" + String.valueOf(min)) : String.valueOf(min);
        final String secStr = (sec < 10) ? ("0" + String.valueOf(sec)) : String.valueOf(sec);
        return minStr + ":" + secStr;
    }
    
    public GameTeam getTeamByName(final String name) {
        for (final GameTeam gameTeam : this.teams) {
            if (gameTeam.getTeamColor().getText().equals(name)) {
                return gameTeam;
            }
        }
        return null;
    }
    
    private void moveFreePlayersToTeam() {
        for (final GameParty gameParty : this.parties) {
            GameTeam lowest = this.getLowestTeam();
            for (final GamePlayer gamePlayer : gameParty.getPlayers()) {
                if (gamePlayer.getGameTeam() == null && !lowest.addPlayer(gamePlayer)) {
                    lowest = this.getLowestTeam();
                }
            }
        }
        for (final GamePlayer gamePlayer2 : MegaWalls.getIngame()) {
            if (gamePlayer2.getGameTeam() == null) {
                final GameTeam lowest = this.getLowestTeam();
                lowest.addPlayer(gamePlayer2);
            }
        }
    }
    
    private GameTeam getLowestTeam() {
        GameTeam lowest = null;
        for (final GameTeam team : this.teams) {
            if (lowest == null) {
                lowest = team;
            }
            else {
                if (team.getGamePlayers().size() >= lowest.getGamePlayers().size()) {
                    continue;
                }
                lowest = team;
            }
        }
        return lowest;
    }
    
    public GameParty getPlayerParty(final GamePlayer gamePlayer) {
        for (final GameParty gameParty : this.parties) {
            if (gameParty.isInTeam(gamePlayer)) {
                return gameParty;
            }
        }
        return null;
    }
    
    public void addParty(final GameParty gameParty) {
        this.parties.add(gameParty);
    }
    
    public void removeParty(final GameParty gameParty) {
        this.parties.remove(gameParty);
    }
    
    public void broadcastMessage(final String message) {
        this.broadcastMessage(message, (GamePlayer[])GamePlayer.getOnlinePlayers().toArray(new GamePlayer[0]));
    }
    
    public void broadcastMessage(final String message, final GamePlayer... gamePlayers) {
        for (final GamePlayer gamePlayer : gamePlayers) {
            gamePlayer.sendMessage(message);
        }
    }
    
    public void broadcastTitle(final String title, final String subtitle, final int fadeIn, final int stay, final int fadeOut) {
        this.broadcastTitle(title, subtitle, fadeIn, stay, fadeOut, (GamePlayer[])GamePlayer.getOnlinePlayers().toArray(new GamePlayer[0]));
    }
    
    public void broadcastTitle(final String title, final String subtitle, final int fadeIn, final int stay, final int fadeOut, final GamePlayer... gamePlayers) {
        for (final GamePlayer gamePlayer : gamePlayers) {
            gamePlayer.sendTitle(title, subtitle, fadeIn, stay, fadeOut);
        }
    }
    
    public void broadcastAction(final String message) {
        this.broadcastAction(message, (GamePlayer[])GamePlayer.getOnlinePlayers().toArray(new GamePlayer[0]));
    }
    
    public void broadcastAction(final String message, final GamePlayer... gamePlayers) {
        for (final GamePlayer gamePlayer : gamePlayers) {
            gamePlayer.sendActionBar(message);
        }
    }
    
    public void broadcastSound(final Sound sound, final float volume, final float pitch) {
        this.broadcastSound(sound, volume, pitch, (GamePlayer[])GamePlayer.getOnlinePlayers().toArray(new GamePlayer[0]));
    }
    
    public void broadcastSound(final Sound sound, final float volume, final float pitch, final GamePlayer... gamePlayers) {
        for (final GamePlayer gamePlayer : gamePlayers) {
            gamePlayer.playSound(sound, volume, pitch);
        }
    }
    
    public String getMapName() {
        return this.mapName;
    }
    
    public GameType getGameType() {
        return this.gameType;
    }
    
    public void setGameType(final GameType gameType) {
        this.gameType = gameType;
    }
    
    public GameState getState() {
        return this.state;
    }
    
    public void setState(final GameState state) {
        this.state = state;
    }
    
    public GameTimer getGameTimer() {
        return this.gameTimer;
    }
    
    public StageManager getStageManager() {
        return this.stageManager;
    }
    
    public Location getLobbyLocation() {
        return this.lobbyLocation;
    }
    
    public GameRegion getCenterArea() {
        return this.centerArea;
    }
    
    public List<GameTeam> getTeams() {
        return this.teams;
    }
    
    public List<GameParty> getParties() {
        return this.parties;
    }
    
    public List<GameWall> getWalls() {
        return this.walls;
    }
    
    public long getStartTime() {
        return this.startTime;
    }
    
    public boolean isWallsFall() {
        return this.wallsFall;
    }
    
    public void setWallsFall(final boolean wallsFall) {
        this.wallsFall = wallsFall;
    }
    
    public boolean isWitherAngry() {
        return this.witherAngry;
    }
    
    public void setWitherAngry(final boolean witherAngry) {
        this.witherAngry = witherAngry;
    }
    
    public boolean isDeathMatch() {
        return this.deathMatch;
    }
    
    public void setDeathMatch(final boolean deathMatch) {
        this.deathMatch = deathMatch;
    }
    
    public GameOverTimer getGameOverTimer() {
        return this.gameOverTimer;
    }
    
    public void setGameOverTimer(final GameOverTimer gameOverTimer) {
        this.gameOverTimer = gameOverTimer;
    }
    
    public int getMinPlayers() {
        return this.minPlayers;
    }
    
    public void setMinPlayers(final int minPlayers) {
        this.minPlayers = minPlayers;
    }
    
    public int getMaxPlayers() {
        return this.maxPlayers;
    }
    
    public void setMaxPlayers(final int maxPlayers) {
        this.maxPlayers = maxPlayers;
    }
    
    public int getTeamSize() {
        return this.teamSize;
    }
    
    public void setTeamSize(final int teamSize) {
        this.teamSize = teamSize;
    }
}
